/*
 * Save2FTP.java
 *
 * Created on November 22, 2005, 2:29 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package org.wiztools.te.plugin;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.wiztools.te.TEMod;
import org.wiztools.te.TEProcess;

/**
 *
 * @author subhash
 */
public class Save2FTP implements TEProcess{
    
    private TEMod tem;
    private Container ct;
    private Container ct_msg;
    
    private JTextField jtf_host;
    private JTextField jtf_port;
    private JCheckBox jcb_anon;
    private JTextField jtf_uid;
    private JPasswordField jpf_pwd;
    private JTextField jtf_folder;
    private JCheckBox jcb_createFolder;
    private JTextField jtf_filename;
    private JRadioButton jrb_bin;
    private JRadioButton jrb_ascii;
    
    private JTextArea jta_msg;
    
    private JButton jb_save;
    private JButton jb_cancel;
    
    public void setTEMod(TEMod tem){
        this.tem = tem;
    }
    
    private JLabel getLabel(String str, char mnemonic, Component c){
        JLabel jl = new JLabel(str);
        jl.setDisplayedMnemonic(mnemonic);
        jl.setLabelFor(c);
        return jl;
    }
    
    private void initMsgContainer(){
        ct_msg = new JPanel();
        
        ct_msg.setLayout(new BorderLayout());
        jta_msg = new JTextArea(25, 30);
        jta_msg.setEditable(false);
        
        ct_msg.add(new JScrollPane(jta_msg), BorderLayout.CENTER);
        
        JPanel jp_south = new JPanel();
        jp_south.setLayout(new FlowLayout());
        
        JButton jb_ok = new JButton("Ok");
        jb_ok.setMnemonic('O');
        jb_ok.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                tem.closeDialog();
                tem.requestFocus();
            }
        });
        jp_south.add(jb_ok);
        
        ct_msg.add(jp_south, BorderLayout.SOUTH);
    }
    
    // Globally define text field size
    private static final int TEXTFIELD_SIZE = 35;
    
    public void init(){
        initMsgContainer();
        
        // Initialize the components
        jtf_host = new JTextField(TEXTFIELD_SIZE);
        
        JPanel jp_port = new JPanel();
        FlowLayout fl = new FlowLayout();
        fl.setAlignment(FlowLayout.LEFT);
        jp_port.setLayout(fl);
        jtf_port = new JTextField("21", 5);
        jtf_port.setEditable(false);
        final JCheckBox jcb_defaultPort = new JCheckBox("Default Port?");
        jcb_defaultPort.setSelected(true);
        jcb_defaultPort.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                if(jcb_defaultPort.isSelected()){
                    jtf_port.setText(String.valueOf(21));
                    jtf_port.setEditable(false);
                }
                else{
                    jtf_port.setEditable(true);
                    jtf_port.requestFocus();
                }
            }
        });
        jp_port.add(jcb_defaultPort);
        jp_port.add(jtf_port);
        
        jcb_anon = new JCheckBox();
        jcb_anon.setSelected(false);
        jcb_anon.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                if(jcb_anon.isSelected()){
                    jtf_uid.setEnabled(false);
                    jpf_pwd.setEnabled(false);
                }
                else{
                    jtf_uid.setEnabled(true);
                    jpf_pwd.setEnabled(true);
                }
            }
        });
        jtf_uid = new JTextField(TEXTFIELD_SIZE);
        jpf_pwd = new JPasswordField(TEXTFIELD_SIZE);
        jtf_folder = new JTextField(TEXTFIELD_SIZE);
        jcb_createFolder = new JCheckBox();
        jcb_createFolder.setSelected(false);
        jtf_filename = new JTextField(TEXTFIELD_SIZE);
        
        jrb_bin = new JRadioButton("Binary");
        jrb_bin.setMnemonic('B');
        jrb_bin.setSelected(true);
        jrb_ascii = new JRadioButton("ASCII");
        jrb_ascii.setMnemonic('I');
        ButtonGroup bg = new ButtonGroup();
        bg.add(jrb_bin);
        bg.add(jrb_ascii);
        
        // Start creating panels and arranging items
        ct = new JPanel();
        ct.setLayout(new BorderLayout());
        
        JPanel jp_north = new JPanel();
        JLabel jl_title = new JLabel("Save 2 FTP");
        jl_title.setHorizontalAlignment(JLabel.CENTER);
        jp_north.add(jl_title);
        ct.add(jp_north, BorderLayout.NORTH);
        
        JPanel jp_west = new JPanel();
        jp_west.setLayout(new GridLayout(9,1));
        jp_west.add(getLabel("Host: ", 'H', jtf_host));
        jp_west.add(new JLabel("Port: "));
        jp_west.add(getLabel("Anonymous: ",  'A', jcb_anon));
        jp_west.add(getLabel("Username: ",  'U', jtf_uid));
        jp_west.add(getLabel("Password: ",  'P', jpf_pwd));
        jp_west.add(getLabel("Folder: ",  'F', jtf_folder));
        jp_west.add(getLabel("Create Folder: ",  'T',  jcb_createFolder));
        jp_west.add(getLabel("File Name: ",  'N', jtf_filename));
        jp_west.add(new JLabel("Mode: "));
        ct.add(jp_west, BorderLayout.WEST);
        
        JPanel jp_center = new JPanel();
        jp_center.setLayout(new GridLayout(9,1));
        
        JPanel jp_center_bg = new JPanel();
        jp_center_bg.setLayout(new FlowLayout());
        jp_center_bg.add(jrb_bin);
        jp_center_bg.add(jrb_ascii);
        
        jp_center.add(jtf_host);
        jp_center.add(jp_port);
        jp_center.add(jcb_anon);
        jp_center.add(jtf_uid);
        jp_center.add(jpf_pwd);
        jp_center.add(jtf_folder);
        jp_center.add(jcb_createFolder);
        jp_center.add(jtf_filename);
        jp_center.add(jp_center_bg);
        ct.add(jp_center, BorderLayout.CENTER);
        
        JPanel jp_south = new JPanel();
        jp_south.setLayout(new FlowLayout());
        jb_save = new JButton("Save");
        jb_save.setMnemonic('S');
        jb_save.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                String host = jtf_host.getText();
                if(host == null || "".equals(host.trim())){
                    showError("Host is invalid!", "Host is invalid!");
                    return;
                }
                int port = -1;
                try{
                    String portStr = jtf_port.getText();
                    port = Integer.parseInt(portStr);
                    if(port < 1){
                        throw new IllegalArgumentException("Port value cannot be less than 1!");
                    }
                }
                catch(NumberFormatException nfe){
                    showError("Invalid port!",  "Invalid port!");
                    return;
                }
                catch(IllegalArgumentException iae){
                    showError("Invalid port!", "Invalid port!");
                    return;
                }
                boolean anon = jcb_anon.isSelected();
                String uid = jtf_uid.getText();
                if(!anon && (uid == null || "".equals(uid.trim()))){
                    showError("Username is invalid!", "Username is invalid!");
                    return;
                }
                String pwd = new String(jpf_pwd.getPassword());
                if(!anon && "".equals(pwd.trim())){
                    showError("Password is null!", "Password is null!");
                    return;
                }
                String folder = jtf_folder.getText();
                if(folder == null || "".equals(folder.trim())){
                    // Taking `pwd` as the upload folder
                }
                boolean createFolder = jcb_createFolder.isSelected();
                String fileName = jtf_filename.getText();
                if(fileName == null || "".equals(fileName.trim())){
                    showError("Filename cannot be null!", "Filename cannot be null!");
                    return;
                }
                boolean asciiMode = jrb_ascii.isSelected();
                
                FTPDetails fd = new FTPDetails();
                fd.host = host;
                fd.port = port;
                fd.anon = anon;
                fd.uid = uid;
                fd.pwd = pwd;
                fd.folder = folder;
                fd.createFolder = createFolder;
                fd.fileName = fileName;
                fd.asciiMode = asciiMode;
                try{
                    String msg = ftpUpload(fd);
                    jta_msg.setText(msg);
                    tem.closeDialog();
                    tem.dispDialog(ct_msg, "FTP Server Messages");
                    
                }
                catch(FTPException ftpe){
                    showError("Error", ftpe.getMessage());
                }
            }
        });
        jb_cancel = new JButton("Cancel");
        jb_cancel.setMnemonic('C');
        jb_cancel.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae){
                tem.closeDialog();
                tem.requestFocus();
            }
        });
        jp_south.add(jb_save);
        jp_south.add(jb_cancel);
        ct.add(jp_south, BorderLayout.SOUTH);
    }
    
    private void showError(String title, String msg){
        JOptionPane.showMessageDialog(tem.getJD(), msg, title, JOptionPane.ERROR_MESSAGE);
    }
    
    private boolean isFTPOperationSuccessful(int reply){
        if(!FTPReply.isPositiveCompletion(reply)) {
            return false;
        }
        return true;
    }
    
    private String ftpUpload(FTPDetails fd) throws FTPException{
        StringBuffer sb = new StringBuffer();
        FTPClient ftp = new FTPClient();
        try{
            InetAddress host = null;
            if("localhost".equalsIgnoreCase(fd.host)){
                host = InetAddress.getLocalHost();
            }
            else{
                host = InetAddress.getByName(fd.host);
            }
            ftp.connect(host, fd.port);
            sb.append("ftp> open ").append(fd.host).append(" ").append(fd.port).append("\n").
                    append(ftp.getReplyString());
            int reply;
            /*if(isFTPOperationSuccessful(ftp.getReplyCode())) {
                throw new FTPException(":-( Connection failed!");
            }*/
            String uid = null;
            String pwd = null;
            if(fd.anon){
                uid = "anonymous";
                pwd = "";
            }
            else{
                uid = fd.uid;
                pwd = fd.pwd;
            }
            ftp.login(uid, pwd);
            sb.append("\nftp> user ").append(fd.uid).append(" ").append(fd.pwd.replaceAll(".", "*")).
                    append("\n").append(ftp.getReplyString());
            /*if(isFTPOperationSuccessful(ftp.getReplyCode())) {
                throw new FTPException("Login failed!");
            }*/
            if(fd.asciiMode){
                ftp.setFileType(FTP.ASCII_FILE_TYPE);
            }
            else{
                ftp.setFileType(FTP.BINARY_FILE_TYPE);
            }
            sb.append("\nftp> ").append(fd.asciiMode?"ascii":"binary").append("\n").
                    append(ftp.getReplyString());
            /*if(isFTPOperationSuccessful(ftp.getReplyCode())) {
                throw new FTPException("Setting File Type failed!");
            }*/
            if(fd.createFolder && fd.folder != null){
                ftp.makeDirectory(fd.folder);
                sb.append("\nftp> mkdir ").append(fd.folder).append("\n").
                        append(ftp.getReplyString());
            }
            /*if(isFTPOperationSuccessful(ftp.getReplyCode())) {
                throw new FTPException("Directory Creation failed!");
            }*/
            String str = tem.getText();
            byte[] arr = str.getBytes();
            ByteArrayInputStream bais = new ByteArrayInputStream(arr);
            final String folderNfile = fd.folder + File.separator + fd.fileName;
            ftp.storeFile(folderNfile, bais);
            sb.append("\nftp> put <BUFFER> ").append(folderNfile).append("\n").
                    append(ftp.getReplyString());
            /*if(isFTPOperationSuccessful(ftp.getReplyCode())) {
                throw new FTPException("Store File failed!");
            }*/
            
            return sb.toString();
        }
        catch(IOException ioe){
            throw new FTPException(ioe.getMessage(), ioe);
        }
        finally{
            // System.out.println(sb);
            if(ftp.isConnected()) {
                try{
                    ftp.logout();
                }
                catch(IOException ioe){
                    ioe.printStackTrace();
                }
                try{
                    ftp.disconnect();
                }
                catch(IOException ioe){
                    ioe.printStackTrace();
                }
            }
        }
    }
    
    public void action(){
        tem.dispDialog(ct, "Save2FTP");
    }
    
    public void destroy(){
        
    }
    
    class FTPDetails{
        String host;
        int port;
        boolean anon;
        String uid;
        String pwd;
        String folder;
        boolean createFolder;
        String fileName;
        boolean asciiMode;
    }
    
    class FTPException extends Exception{
        public FTPException(String msg, Throwable thr){
            super(msg, thr);
        }
        
        public FTPException(String msg){
            super(msg);
        }
    }
}
